﻿using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding;
using LunarSF.SHomeWorkshop.LunarMarkdownEditor.PythonAnalysis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    public class PythonEditBase : TextEditor
    {
        public PythonEditBase()
        {
            this.SnapsToDevicePixels = true;//避免折叠线模糊
            this.Background = Brushes.WhiteSmoke;
            RenderOptions.SetEdgeMode(this, EdgeMode.Aliased);

            this.WordWrap = true;

            this.TextArea.SelectionBorder = new Pen(Brushes.Transparent, 1);
            this.TextArea.SelectionBrush = new SolidColorBrush(Color.FromArgb(255, 145, 83, 0));  // Color.FromArgb(255, 240, 106, 0) 是那两条行高亮线色
            this.TextArea.SelectionCornerRadius = 0;

            this.PreviewKeyDown += PythonEditBase_PreviewKeyDown;

            #region 自动完成
            this.TextArea.TextEntered += TextArea_TextEntered;
            this.TextArea.TextEntering += TextArea_TextEntering;
            #endregion

            #region 内置的自动完成列表
            // 添加 Python 关键字
            var pyKeyWords = new string[] {
                "False",
                "None",
                "True",
                "and",
                "as",
                "assert",
                "async",
                "await",
                "break",
                "class",
                "continue",
                "def",
                "del",
                "elif",
                "else",
                "except",
                "finally",
                "for",
                "from",
                "global",
                "if",
                "import",
                "in",
                "is",
                "lambda",
                "nonlocal",
                "not",
                "or",
                "pass",
                "raise",
                "return",
                "try",
                "while",
                "with",
                "yield",
            };
            foreach (var keyWord in pyKeyWords)
            {
                innerCompletionData.Add(new CustomCompletionData(keyWord, "Python 关键词", keyWord));
            }

            //添加常用词
            var pyCommonWords = new string[] {
                "main",
                "self",
            };
            foreach (var commonWord in pyCommonWords)
            {
                innerCompletionData.Add(new CustomCompletionData(commonWord, "常用词", commonWord));
            }

            // inputText
            // documentText
            // ignoreTextChanging
            // pathToWorkspace
            // pathOfWorkspace
            // psArgs
            //     Ae       此行以后属于 psArgs.Ae 
            //     Ate
            //     GetAllFilePathsOfWorkspace()
            //     HtmlFileName
            //     HtmlFilePath
            //     MdFileInfo
            //     MdFileName
            //     MdFilePath

            var lmeArgs = @"inputText|documentText|ignoreTextChanging|pathToWorkspace|pathOfWorkspace|psArgs|Ate|GetAllFilePathsOfWorkspace()|HtmlFileName|HtmlFilePath|MdFileInfo|MdFileName|MdFilePath".Split(new char[] { '|', }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var lmeArg in lmeArgs)
            {
                innerCompletionData.Add(new CustomCompletionData(lmeArg.EndsWith("()") ? lmeArg.Substring(0, lmeArg.Length - 1) : lmeArg, "调用脚本时传入的参数", lmeArg));
            }

            #endregion 内置的自动完成列表
        }

        #region 自动完成

        private List<ICompletionData> innerCompletionData = new List<ICompletionData>();

        private void TextArea_TextEntering(object sender, TextCompositionEventArgs e)
        {
            if ((e.Text == "." || e.Text == " " || e.Text == ":") && CompletionWindow != null && CompletionWindow.Visibility == Visibility.Visible)
            {
                var selItem = CompletionWindow.CompletionList.SelectedItem;
                if (selItem != null)
                {
                    var line = this.Document.GetLineByOffset(this.SelectionStart);
                    if (line == null) return;
                    var currentOffsetInLine = this.SelectionStart - line.Offset;
                    var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

                    var tailSpaceCount = 0;
                    for (int i = lineLeftText.Length - 1; i >= 0; i--)
                    {
                        if (lineLeftText[i] == ' ') { tailSpaceCount++; }
                        else break;
                    }

                    if (tailSpaceCount > 0)
                    {
                        lineLeftText = lineLeftText.TrimEnd(new char[] { ' ', });
                    }

                    var lastIndexOfInvalidateChar = -1;
                    for (int i = lineLeftText.Length - 1; i >= 0; i--)
                    {
                        var c = lineLeftText[i];
                        // if (c == '.') continue;  // 这句不能加，否则会把 . 之前的也替换掉。
                        if (IsValidateChar(c)) continue;

                        lastIndexOfInvalidateChar = i;
                        break;
                    }

                    var start = this.SelectionStart;
                    var length = this.SelectionLength;
                    if (lastIndexOfInvalidateChar >= 0)
                    {
                        start = line.Offset + lastIndexOfInvalidateChar + 1;
                        length = lineLeftText.Length - lastIndexOfInvalidateChar - 1 + tailSpaceCount;
                    }
                    else
                    {
                        var leftWhiteCharsCount = 0;
                        foreach (var lc in lineLeftText)
                        {
                            if (lc == ' ' || lc == '\t')
                                leftWhiteCharsCount++;
                            else break;
                        }

                        start = line.Offset + leftWhiteCharsCount;
                        length = lineLeftText.Length - leftWhiteCharsCount;
                    }

                    selItem.Complete(this.TextArea, new AnchorSegment(this.TextArea.Document, start, length), e);

                    // 加个空格
                    this.TextArea.Document.Insert(this.SelectionStart, e.Text);

                    completionWindow.Close();
                    completionWindow = null;
                    e.Handled = true;
                }

                if (e.Text == "." || e.Text == " ")
                {
                    ShowCompleteWindow(e);
                }
                return;
            }

            // 注意：与输入 Markdown 不同：输入 Python 代码时，即使变量名使用中文，
            // 也不是输入每个字都需要刷新自动完成列表的数据项的。
            // 大体上，只有这么几种情况需要刷新数据项：
            //     ①输入空格后
            //     ②输入标点后（如赋值号 = 或 运算符号后）
            //     ③输入某些 Python 关键词后（如 import、from、for 等）后
            //     ④输入句点符号后（这个是重点）
            //     ⑤输入左括号后（例如指定 class 的基类）

            // 全部在 TextArea_TextEntered 事件中处理。
            //var line = this.Document.GetLineByOffset(this.SelectionStart);
            //if (line == null) return;
            //var currentOffsetInLine = this.SelectionStart - line.Offset;
            //var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

            //if (completionWindow == null)
            //{
            //    completionWindow = new CompletionWindow(this.TextArea)
            //    {
            //        MinHeight = 34,
            //        MinWidth = 100,
            //    };
            //}

            //IList<ICompletionData> data = CompletionWindow.CompletionList.CompletionData;

            //if (ShowBlankLineCompletion(line, lineLeftText, e.Text, ref data)) return;  // Python 允许嵌套方法
        }



        /// <summary>
        /// 处理 from xxx 或 import xxx 中对 xxx 的自动完成提示。
        /// </summary>
        private bool ShowFromOrImportCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // from import 语句
            var regFrom = new Regex(@"^((from)|(import)) {1,}$");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                var ipLibInfo = new DirectoryInfo(Globals.InstalledPath + "Lib\\");
                var files = ipLibInfo.GetFiles("*.py");
                foreach (var file in files)
                {
                    if (file.Name.StartsWith("_")) continue;

                    var shortName = file.Name.EndsWith(".py") ? file.Name.Substring(0, file.Name.Length - 3) : file.Name;
                    if (shortName == "clrtype")
                    {
                        // 放在这里可在省去排序。
                        // 这个要单独处理，在 IronPython Lib 目录中找不到对应模块文件，应该是内置的。
                        data.Add(new CustomCompletionData("clr", "引用 .net 程序集", "clr"));
                    }

                    data.Add(new CustomCompletionData(shortName, "可导入的 IronPython 模块", shortName));
                }

                var userPythonModelDirectory = new DirectoryInfo(Globals.PathOfPythonScripts);
                var userScriptFiles = userPythonModelDirectory.GetFiles("*.py");
                foreach (var userScriptFile in userScriptFiles)
                {
                    if (userScriptFile.Name.StartsWith("_")) continue;

                    var shortName = userScriptFile.Name.EndsWith(".py") ? userScriptFile.Name.Substring(0, userScriptFile.Name.Length - 3) : userScriptFile.Name;

                    data.Add(new CustomCompletionData(shortName, "可导入的 用户脚本 模块", shortName));
                }

                //TODO: 可引入的 IronPython 包，这个暂时不支持
                var directories = ipLibInfo.GetDirectories();
                foreach (var directory in directories)
                {
                    string initFilePath;

                    if (directory.FullName.EndsWith("\\"))
                    {
                        initFilePath = directory.FullName + "__init__.py";
                    }
                    else
                    {
                        initFilePath = directory.FullName + "\\__init__.py";
                    }

                    if (File.Exists(initFilePath))
                    {
                        data.Add(new CustomCompletionData(directory.Name, "可导入的 IronPython 包", directory.Name));
                    }
                }

                // 引入 LME 命名空间
                data.Add(new CustomCompletionData("LunarSF", "LME 命名空间前缀", "LunarSF"));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 处理 from xxx import 中的 import 的提示。
        /// </summary>
        private bool ShowFromImportCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // from import 语句
            var regFrom = new Regex(@"^from {1,}[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,} {1,}$");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                data.Add(new CustomCompletionData("import", "Python 关键词", "import"));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 处理 from xxx.yyy.zzz import abcd 中对 abcd 的提示。
        /// </summary>
        private bool ShowFromImportModelCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            var regFrom = new Regex(@"(?<=(^from {1,}))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}){0,}(?= {1,}import {1,}$)");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                var modelShortPath = matchFrom.Value.Replace(".", "\\");
                var libPath = Globals.InstalledPath + "Lib\\";
                var modelPath = libPath + modelShortPath + ".py";

                var pythonModelInfo = GetPythonModelInfo(modelShortPath);
                if (pythonModelInfo == null)
                {
                    if (File.Exists(modelPath) == false)
                    {
                        // 如果不是 IronPython 模块，则看是否用户自定义模块
                        modelPath = Globals.PathOfPythonScripts + modelShortPath + ".py";
                    }

                    if (File.Exists(modelPath))
                    {
                        pythonModelInfo = new PythonModelInfo()
                        {
                            ModelName = modelShortPath,
                            ModelPath = modelPath,
                        };
                        PythonModelInfo.ReadElementInfos(modelPath, ref pythonModelInfo);
                        pythonModelInfos.Add(pythonModelInfo);
                    }
                    else
                    {
                        // 在 IronPython 模块和当前用户脚本目录下都找不到，可能是 .net 程序集。
                        var clrReferenceLines = GetImportedClrReferenceLines(1, line.LineNumber - 1);
                        modelShortPath = modelShortPath.Replace("\\", ".");

                        foreach (var clrReferenceLine in clrReferenceLines)
                        {
                            if (Globals.AppFileName.ToLower().StartsWith(clrReferenceLine.ToLower() + ","))
                            {
                                // 通常是引用 LME 自身

                            }
                            //if (File.Exists(Globals.InstalledPath + clrReferenceLine + ".exe"))
                            //{

                            //}
                            // TODO: 为安全考虑，暂不支持引用外部动态链接库
                            //else if (File.Exists(Globals.InstalledPath + clrReferenceLine + ".dll"))
                            //{
                            //    // 引用运行目录下某个 dll

                            //}
                            else return false;  //TODO： 暂时不支持引用 .net 程序集
                            //{
                            //    // 引用 .net 程序集

                            //}
                        }
                    }
                }

                if (pythonModelInfo == null || pythonModelInfo.Elements.Count <= 0) return false;

                foreach (var element in pythonModelInfo.Elements)
                {
                    // if (element.ElementName.StartsWith("_")) continue;  // 以下划线开头的仅“标明”是个内部方法，但实际上仍可访问，所以不应该被屏蔽！

                    data.Add(new CustomCompletionData(element.ElementName, element.ElementType.ToString(), element.ElementName));
                }

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        private bool ShowFromImportPackageCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // 处理 from xxx import yyy 语句
            var regFrom = new Regex(@"(?<=(^from {1,}))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}){0,}\.(?= {1,}import {1,}$)");
            var matchFrom = regFrom.Match(lineLeftText + inputText);
            if (matchFrom.Success)
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();

                var packageShortPath = matchFrom.Value.Replace(".", "\\");
                if (packageShortPath.EndsWith("\\") == false)
                    packageShortPath += "\\";
                var libPath = Globals.InstalledPath + "Lib\\";
                var packagePath = libPath + packageShortPath;

                //TODO: 要考虑 IronPython 包和用户包之间的关系

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 处理 clr.AddReference() 中对 AddReference 的提示
        /// </summary>
        private bool ShowClrAddReferenceCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if (lineLeftText == "clr." && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("AddReference", "引用 .net 类型的方法", "AddReference"));

                ShowCompletionWindow();
                return true;
            }
            else if (lineLeftText == "clr.AddReference(" && inputText == "(")
            {
                data.Clear();

                data.Add(new CustomCompletionData("\"LunarMarkdownEditor\"", "引用 LME", "\"LunarMarkdownEditor\""));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 对类与命名空间的提示。
        /// </summary>
        private bool ShowLmeClassCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if ((lineLeftText == "from LunarSF." || lineLeftText == "import LunarSF.") && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("SHomeWorkshop", "引用 LME 命名空间", "SHomeWorkshop"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop." || lineLeftText == "import LunarSF.SHomeWorkshop.") && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("LunarMarkdownEditor", "引用 LME 命名空间", "LunarMarkdownEditor"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor." || lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor.") && inputText == ".")
            {
                data.Clear();

                data.Add(new CustomCompletionData("Utils", "LME 工具类集", "Utils"));
                data.Add(new CustomCompletionData("Widgets", "LME 部件类集", "Widgets"));

                ShowCompletionWindow();
                return true;
            }
            else if (lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils " ||
                lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets ")
            {
                data.Clear();
                data.Add(new CustomCompletionData("import", "Python 关键字", "import"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils import " && inputText == " ") ||
                (lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils." && inputText == "."))
            {
                data.Clear();
                data.Add(new CustomCompletionData("HtmlTag", "LME 工具类", "LButton"));
                data.Add(new CustomCompletionData("LFile", "LME 工具类", "LButton"));
                data.Add(new CustomCompletionData("Speech", "LME 工具类", "Speech"));
                data.Add(new CustomCompletionData("Text", "LME 工具类", "Text"));

                // 在 IronPython 中调用 WebBrowser 的 LoadCompleted 事件不起作用，不建议使用。
                //data.Add(new CustomCompletionData("Text", "LME 工具类", "Web"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets import " && inputText == " ") ||
                (lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets." && inputText == "."))
            {
                data.Clear();
                data.Add(new CustomCompletionData("LButton", "LME 按钮类", "LButton"));
                data.Add(new CustomCompletionData("LWindow", "LME 窗口类", "LWindow"));

                ShowCompletionWindow();
                return true;
            }
            else if (lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor ")
            {
                data.Clear();
                data.Add(new CustomCompletionData("import", "Python 关键字", "import"));

                ShowCompletionWindow();
                return true;
            }
            else if ((lineLeftText == "from LunarSF.SHomeWorkshop.LunarMarkdownEditor import " && inputText == " ") ||
                (lineLeftText == "import LunarSF.SHomeWorkshop.LunarMarkdownEditor." && inputText == "."))
            {
                // 只提供常用类的建议列表
                data.Clear();

                data.Add(new CustomCompletionData("BrushManager", "LME 常用工具类", "BrushManager"));
                data.Add(new CustomCompletionData("CheckBoxItem", "LME 常用部件类", "CheckBoxItem"));
                data.Add(new CustomCompletionData("ChinesePinYin", "LME 常用工具类", "ChinesePinYin"));
                data.Add(new CustomCompletionData("CustomMarkdownSupport", "LME 常用工具类", "CustomMarkdownSupport"));
                data.Add(new CustomCompletionData("Globals", "LME 常用工具类", "Globals"));
                data.Add(new CustomCompletionData("InputBox", "LME 常用部件类", "InputBox"));
                data.Add(new CustomCompletionData("LMessageBox", "LME 常用部件类", "LMessageBox"));
                data.Add(new CustomCompletionData("MainWindow", "LME 常用部件类", "MainWindow"));
                data.Add(new CustomCompletionData("MarkdownEditor", "LME 常用部件类", "MarkdownEditor"));
                data.Add(new CustomCompletionData("XmlTools", "LME 常用工具类", "XmlTools"));

                ShowCompletionWindow();
                return true;
            }
            return false;
        }

        /// <summary>
        /// 对变量的提示。
        /// </summary>
        private bool ShowVariablesCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if (string.IsNullOrWhiteSpace(lineLeftText)) return false;

            if (inputText == ".")
            {
                var fstBodyLineNumber = GetFirstNoneImportLineNumber();
                if (line.LineNumber < fstBodyLineNumber) return false;

                AnalysisImportedElements(1, fstBodyLineNumber);

                var lastIndexOfInvalidateChar = -1;
                for (int i = lineLeftText.Length - 1; i >= 0; i--)
                {
                    var c = lineLeftText[i];
                    if (c == '.') continue;
                    if (IsValidateChar(c)) continue;

                    lastIndexOfInvalidateChar = i;
                    break;
                }

                if (lastIndexOfInvalidateChar < 0 || lastIndexOfInvalidateChar >= lineLeftText.Length - 1) return false;

                var varMark = lineLeftText.Substring(lastIndexOfInvalidateChar + 1).Trim(new char[] { '.', });
                // 此时 varMark 应该形如 xxx.yyyy.ab 或者就是 xxx 等等

                if (varMark.IndexOf(".") >= 0)
                {
                    foreach (var ie in importedElements)
                    {
                        switch (ie.Type)
                        {
                            case ImportedElementType.PythonPackage:
                                // 提示包中下属的子包名、模块名
                                // 暂时不考虑 __init__.py 中公开的方法等情况
                                break;
                            case ImportedElementType.PythonModel:
                                // 提示下属的方法、全局变量、类等
                                break;
                            case ImportedElementType.DotNetNamespace:
                                // 提示下级命名空间或者类名
                                break;
                            case ImportedElementType.DotNetClass:
                                // 提示下属的成员（方法、属性、公开字段等）
                                break;
                        }
                    }
                }
                else
                {
                    // 就是当前文件中某个类，找出其成员并提示


                }
            }

            return false;
        }

        /// <summary>
        /// 鉴于全面实现智能感知实在太复杂，改为“提示文本片段”会容易实现得多。所以暂时就做这样的一个临时功能。
        /// </summary>
        private bool ShowPiecesCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            // 从当前行的前一行开始向前倒找
            if (line.LineNumber > 1)
            {
                data.Clear();

                // 内置变量名、Python 关键词等。
                foreach (var innerItem in innerCompletionData)
                {
                    data.Add(innerItem);
                }

                List<string> addedItems = new List<string>();
                var trimChars = new char[] { ' ', '\t', };

                var regPiece = new Regex(@"[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}");
                var regEnPiece = new Regex(@"[a-zA-Z][a-zA-Z0-9_]{0,}");

                for (int i = line.LineNumber; i >= 1; i--)
                {
                    var iLine = this.Document.GetLineByNumber(i);
                    var iText = this.Document.GetText(iLine.Offset, iLine.Length);
                    if (iText.TrimStart(trimChars).StartsWith("#"))
                    {
                        var iepMatches = regEnPiece.Matches(iText);
                        if (iepMatches.Count > 0)
                        {
                            foreach (Match ipm in iepMatches)
                            {
                                Console.WriteLine("aaa:" + ipm.Value);
                                if (Exists(data, ipm.Value) || string.IsNullOrWhiteSpace(ipm.Value)) continue;
                                var newData = new CustomCompletionData(ipm.Value, "文本片段或变量名", ipm.Value);
                                data.Add(newData);
                            }
                        }
                    }
                    else
                    {
                        var ipMatches = regPiece.Matches(iText);
                        if (ipMatches.Count > 0)
                        {
                            foreach (Match ipm in ipMatches)
                            {
                                Console.WriteLine("bbb:" + ipm.Value);

                                //data.Add(new CustomCompletionData(ipm.Value, "文本片段或变量名", ipm.Value));
                                if (Exists(data, ipm.Value) || string.IsNullOrWhiteSpace(ipm.Value)) continue;
                                var newData = new CustomCompletionData(ipm.Value, "文本片段或变量名", ipm.Value);
                                data.Add(newData);
                            }
                        }
                    }
                }

                if (data.Count > 0)
                {
                    ShowCompletionWindow();
                    return true;
                }

                return false;
            }

            return false;
        }

        private bool Exists(IList<ICompletionData> data, string value)
        {
            if (data == null || data.Count <= 0) return false;
            foreach (ICompletionData id in data)
            {
                if (id.Text == value) return true;
            }
            return false;
        }

        /// <summary>
        /// 提示当前文件中的变量或类名或方法名.
        /// </summary>
        private bool ShowInnerVariablesCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            var trimedLeftText = lineLeftText.TrimEnd();
            if (string.IsNullOrWhiteSpace(trimedLeftText) == false)
            {
                if (trimedLeftText.EndsWith(" and") == false &&
                    trimedLeftText.EndsWith(" or") == false &&
                    trimedLeftText.EndsWith("*") == false &&
                    trimedLeftText.EndsWith("/") == false &&
                    trimedLeftText.EndsWith("+") == false &&
                    trimedLeftText.EndsWith("-") == false &&
                    trimedLeftText.EndsWith("%") == false &&
                    trimedLeftText.EndsWith("=") == false &&
                    trimedLeftText.EndsWith("<") == false &&
                    trimedLeftText.EndsWith(">") == false)
                    return false;
            }

            // 要注意对内置方法的提示 例如 len() 等。
            // 先处理当前文档中的变量

            // 从当前行的前一行开始向前倒找
            if (line.LineNumber > 1)
            {
                data.Clear();
                List<string> addedItems = new List<string>();

                var regVariablesLine = new Regex(@"(?<=(^[ \t]*))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})( *(, {0,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})))*(?=( *[=]))");
                var regMethodLine = new Regex(@"(?<=(^[ \t]*def {1,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}) {0,}\( {0,}))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})( *(, {0,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})))*(?=( *\)))");
                var currentLineLevel = GetLineLevel(lineLeftText);
                var levelPoint = currentLineLevel;
                var methodMatched = false;
                var myMethodLevel = -1;
                for (int i = line.LineNumber - 1; i >= 1; i--)
                {
                    var iLine = this.Document.GetLineByNumber(i);
                    var iText = this.Document.GetText(iLine.Offset, iLine.Length);
                    var iLevel = GetLineLevel(iText);
                    if (iLevel < 0) continue;

                    var ivMatch = regVariablesLine.Match(iText);
                    if (ivMatch.Success)
                    {
                        if (iLevel > levelPoint) continue;
                        else if (iLevel <= levelPoint)
                        {
                            var varsText = ivMatch.Value;
                            if (string.IsNullOrWhiteSpace(varsText)) continue;
                            var vars = varsText.Split(new char[] { ',', ' ', }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (var v in vars)
                            {
                                if (addedItems.Contains(v) == false)
                                {
                                    data.Add(new CustomCompletionData(v, "当前文件中的变量", v));
                                    addedItems.Add(v);
                                }
                            }
                            if (iLevel < levelPoint) levelPoint = iLevel;

                            continue;
                        }
                    }

                    if (myMethodLevel >= 0 && iLevel >= myMethodLevel && methodMatched) continue;

                    var iaMatch = regMethodLine.Match(iText);
                    if (iaMatch.Success)
                    {
                        if (iLevel > levelPoint) continue;
                        else if (iLevel <= levelPoint)
                        {
                            myMethodLevel = iLevel;
                            methodMatched = true;
                            var argsText = iaMatch.Value;
                            if (string.IsNullOrEmpty(argsText)) continue;
                            var args = argsText.Split(new char[] { ',', ' ', }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (var a in args)
                            {
                                if (addedItems.Contains(a) == false)
                                {
                                    data.Add(new CustomCompletionData(a, "参数", a));
                                    addedItems.Add(a);
                                }
                            }
                            if (iLevel < levelPoint) levelPoint = iLevel;

                            continue;
                        }
                    }
                }

                // 最后考虑当前行中有没有可以使用的变量
                if (string.IsNullOrWhiteSpace(lineLeftText) == false)
                {
                    var currentLineMatch = regVariablesLine.Match(lineLeftText);
                    if (currentLineMatch.Success)
                    {
                        var cVarsText = currentLineMatch.Value;
                        var cVars = cVarsText.Split(new char[] { ',', ' ', }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var c in cVars)
                        {
                            if (addedItems.Contains(c) == false)
                            {
                                data.Add(new CustomCompletionData(c, "局部变量", c));
                                addedItems.Add(c);
                            }
                        }
                    }
                }

                if (data.Count > 0)
                {
                    ShowCompletionWindow();
                    return true;
                }

                return false;
            }

            return false;
        }

        private int GetLineLevel(string lineText)
        {
            if (string.IsNullOrWhiteSpace(lineText)) return -1;  // 无意义

            lineText = lineText.Replace("\t", "    ");
            var count = 0;
            foreach (var c in lineText)
            {
                if (c == ' ') count++;
                else break;
            }

            if (count % 4 == 0) return count / 4;

            return -1;
        }

        /// <summary>
        /// 提供 Python 关键字的自动提示。
        /// </summary>
        private bool ShowBlankLineCompletion(DocumentLine line, string lineLeftText, string inputText, ref IList<ICompletionData> data)
        {
            if (string.IsNullOrWhiteSpace(lineLeftText))
            {
                // 清除自动完成列表并重新添加其中的项目。
                data.Clear();
                ShowInnerVariablesCompletion(line, lineLeftText, inputText, ref data);
                foreach (var innerItem in innerCompletionData)
                {
                    data.Add(innerItem);
                }
                ShowCompletionWindow();
                return true;
            }

            return false;
        }

        private void ShowCompletionWindow()
        {
            CompletionWindow.Show();
            CompletionWindow.Closed += delegate
            {
                completionWindow = null;
            };
        }

        private void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
        {
            // if (e.Text != ".") return;  // 太烦人了

            if (e.Text.Length <= 0 || e.Text == "\r\n")
            {
                if (completionWindow != null)
                {
                    completionWindow.Close();
                    completionWindow = null;
                }
                return;
            }

            ShowCompleteWindow(e);

            // Do not set e.Handled=true.
            // We still want to insert the character that was typed.
        }

        private void ShowCompleteWindow(TextCompositionEventArgs e)
        {
            if (IsValidateChars(e.Text) == false)
            {
                var line = this.Document.GetLineByOffset(this.SelectionStart);
                if (line == null) return;

                var currentOffsetInLine = this.SelectionStart - line.Offset;
                var lineLeftText = this.Document.GetText(line.Offset, currentOffsetInLine);

                if (lineLeftText.StartsWith("#") || lineLeftText.Trim(new char[] { ' ', '\t', }).Length <= 0) return;

                completionWindow = new CompletionWindow(this.TextArea)
                {
                    MinHeight = 34,
                    MinWidth = 100,
                };

                IList<ICompletionData> data = CompletionWindow.CompletionList.CompletionData;

                // 根据情况生成自动完成窗口及其中的项目
                //if (ShowFromOrImportCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowFromImportCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowFromImportModelCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowClrAddReferenceCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowLmeClassCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowVariablesCompletion(line, lineLeftText, e.Text, ref data)) return;
                //if (ShowInnerVariablesCompletion(line, lineLeftText, e.Text, ref data)) return;
                if (ShowPiecesCompletion(line, lineLeftText, e.Text, ref data)) return;

                if (data.Count > 0)
                {
                    // 完成插入，销毁自动完成窗口
                    CompletionWindow.CompletionList.RequestInsertion(e);
                    CompletionWindow.Close();
                    completionWindow = null;
                }
                else
                {
                    if (CompletionWindow != null)
                    {
                        CompletionWindow.Hide();
                    }
                }
                return;
            }
        }

        /// <summary>
        /// 是否均为可用标识符。包括 _ 字母 英文 中文字符(Unicode 19968-40869)。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private bool IsValidateChars(string text)
        {
            if (string.IsNullOrWhiteSpace(text)) return false;
            if (text.Contains('\r') || text.Contains('\n') || text.Contains('\t') || text.Contains(' ')) return false;

            foreach (var c in text)
            {
                if (c == '_') continue;
                if (c >= '0' && c <= '9') continue;
                if (c >= 'a' && c <= 'z') continue;
                if (c >= 'A' && c <= 'Z') continue;
                var v = (int)c;
                if (v >= 19968 && v <= 40869) continue;  // \u4E00-\u9FA5

                return false;
            }

            return true;
        }

        /// <summary>
        /// 是否英文字母、数字、下划线字符或 \u4E00-\u9FA5 之间的汉字。
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private bool IsValidateChar(char c)
        {
            if (c == '_') return true;
            if (c >= '0' && c <= '9') return true;
            if (c >= 'a' && c <= 'z') return true;
            if (c >= 'A' && c <= 'Z') return true;
            var v = (int)c;
            if (v >= 19968 && v <= 40869) return true;  // \u4E00-\u9FA5

            return false;
        }

        private void PythonEditBase_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            bool isCtrl = false ||
                (Keyboard.GetKeyStates(Key.RightCtrl) & KeyStates.Down) > 0 ||
                (Keyboard.GetKeyStates(Key.LeftCtrl) & KeyStates.Down) > 0;

            bool isShift = false ||
                (Keyboard.GetKeyStates(Key.RightShift) & KeyStates.Down) > 0 ||
                (Keyboard.GetKeyStates(Key.LeftShift) & KeyStates.Down) > 0;

            bool isAlt = false ||
                (Keyboard.GetKeyStates(Key.RightAlt) & KeyStates.Down) > 0 ||
                (Keyboard.GetKeyStates(Key.LeftAlt) & KeyStates.Down) > 0;

            try
            {
                switch (e.Key)
                {
                    case Key.I://为什么在这里处理？因为avalonEdit已经绑死Alt+Up，使用Alt+Up不起任何作用。其实用覆盖 OnKeyDown() 方法的办法可以解决。
                        {
                            if (isCtrl)//移动到上一行的上方。
                            {
                                if (isShift)
                                {
                                    if (!isAlt) SwapWithPreviewLine();
                                }
                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.K://为什么用这个？因为avalonEdit已经绑死Alt+Up，使用Alt+Up不起任何作用。其实用覆盖 OnKeyDown() 方法的办法可以解决。
                        {
                            if (isCtrl && isShift && !isAlt)//移动到下一行的下方。
                            {
                                SwapWithNextLine();

                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.Back://BackSpace，退格键
                        {
                            if (isShift && !isCtrl && !isAlt)
                            {
                                //删除到行首
                                var textArea = this.TextArea;
                                if (textArea != null && textArea.IsKeyboardFocused)
                                {
                                    var curLine = this.Document.GetLineByOffset(this.SelectionStart);
                                    var curLineText = this.Document.GetText(curLine.Offset, curLine.Length);

                                    var fstSelectedLine = this.Document.GetLineByOffset(this.SelectionStart);

                                    this.Select(fstSelectedLine.Offset, textArea.Selection.Length + (this.SelectionStart - fstSelectedLine.Offset));
                                    textArea.PerformTextInput("");

                                    e.Handled = true;
                                }
                            }
                            break;
                        }
                    case Key.Enter://回车键
                        {
                            if (isCtrl)
                            {
                                if (!isShift)
                                {
                                    //在当前行下方插入一个新行，并移动光标。
                                    AppendANewLine();
                                    e.Handled = true;
                                }
                            }
                            else
                            {
                                if (isShift)
                                {
                                    //在当前行上方插入一个新行，并移动光标。
                                    InsertANewLine();
                                    e.Handled = true;
                                }
                                else
                                {
                                    e.Handled = BreakLine();
                                }

                                //AvalonEdit有个默认行为：若一行文本以空格开头，无论在第一个非空格字符前按下回车，还是在这些空格前按下回车，
                                //新行开头都不会保留空格！！！
                            }
                            break;
                        }
                    case Key.Tab://Tab键
                        {
                            if (!isCtrl && !isAlt)
                            {
                                if (isShift)
                                {
                                    if (JumpOverMarks(ref e, isShift)) return;
                                }
                                else
                                {
                                    //跳过反引号，用在：按Ctrl+`输入一对反引号并将插入点置于两个反引号之间，输入一些文本后直接跳过右反引号继续输入其它文本。
                                    //这比按两个组合方向按键跳过去或者按方向键跳过去更方便。
                                    //*号对与_对情形类似。

                                    if (JumpOverMarks(ref e, isShift)) return;
                                }
                            }
                            break;
                        }
                    case Key.Z:
                        {
                            if (!isAlt)
                            {
                                if (!isShift && isCtrl)
                                {
                                    if (this.CanUndo) this.Undo();
                                    e.Handled = true;
                                }
                            }
                            break;
                        }
                    case Key.Y:
                        {
                            if (!isAlt && !isShift && isCtrl)
                            {
                                if (this.CanRedo) this.Redo();
                                e.Handled = true;
                            }
                            break;
                        }
                    case Key.C:
                        {
                            if (isCtrl && isShift && !isAlt)
                            {
                                if (this.SelectedText.Length <= 0)
                                {
                                    // 复制当前行到新行
                                    var selLine = this.Document.GetLineByOffset(this.SelectionStart);
                                    var selLineText = this.Document.GetText(selLine.Offset, selLine.Length);
                                    var oldSelOffset = this.SelectionStart - selLine.Offset;
                                    if (selLineText.EndsWith("\r\n"))
                                    {
                                        this.Select(selLine.EndOffset, 0);
                                        this.SelectedText = selLineText;
                                        this.Select(this.SelectionStart + oldSelOffset, 0);
                                    }
                                    else
                                    {
                                        this.Select(selLine.EndOffset, 0);
                                        this.SelectedText = "\r\n" + selLineText;
                                        this.Select(this.SelectionStart + oldSelOffset + 2, 0);
                                    }
                                    e.Handled = true;
                                }
                            }
                            break;
                        }
                }
            }
            catch (Exception ex)
            {
                LMessageBox.Show("发生意外错误，无法执行操作。建议保存文件并重启程序。\r\n" +
                    ex.Message + "\r\n" + ex.StackTrace, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        private CompletionWindow completionWindow;
        /// <summary>
        /// 自动完成窗口。
        /// </summary>
        public CompletionWindow CompletionWindow
        {
            get
            {
                return completionWindow;
            }
        }

        private List<PythonModelInfo> pythonModelInfos = new List<PythonModelInfo>();

        private PythonModelInfo GetPythonModelInfo(string pyModelName)
        {
            if (string.IsNullOrWhiteSpace(pyModelName)) return null;

            foreach (var pi in pythonModelInfos)
            {
                if (pi.ModelName != null && pi.ModelName == pyModelName)
                    return pi;
            }
            return null;
        }


        /// <summary>
        /// 取 import clr 语句所在的行号（从1开始），如果小于等于0，则表示从“当前行向前的所有行中都没有找到”。
        /// </summary>
        private int GetClrImportedLineNumber(DocumentLine curLine)
        {
            var regClrImported = new Regex(@"^import {1,}clr.*$");
            var trimChars = new char[] { ' ', };
            for (int i = 1; i < curLine.LineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                if (regClrImported.Match(lineText).Success) return i;
            }
            return -1;
        }

        /// <summary>
        /// 取所有 cla.AddReference("xxx") 行。
        /// </summary>
        private List<string> GetImportedClrReferenceLines(int startLineNumber, int endLineNumber)
        {
            var resultList = new List<string>();
            var regClrAddReference = new Regex(@"(?<=(^clr.AddReference\([""']))([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})((\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}){0,})(?=([""']\)))");
            var trimChars = new char[] { ' ', };
            for (int i = startLineNumber; i <= endLineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                var match = regClrAddReference.Match(lineText);
                if (match.Success)
                {
                    resultList.Add(match.Value);
                }
            }
            return resultList;
        }

        /// <summary>
        /// 取所有形如 from xxx.yyy.zzz import abcd as ef 这样的行。
        /// </summary>
        private List<string> GetFromImportedLine(int startLineNumber, int endLineNumber)
        {
            var resultList = new List<string>();
            var regFromImportLine = new Regex(@"(?<=(^from {1,})([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}) {1,}import {1,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})( {1,}as ([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})))");
            var trimChars = new char[] { ' ', };
            for (int i = startLineNumber; i <= endLineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                var match = regFromImportLine.Match(lineText);
                if (match.Success)
                {
                    resultList.Add(lineText);
                }
            }
            return resultList;
        }

        private List<string> GetImportedLine(int startLineNumber, int endLineNumber)
        {
            var resultList = new List<string>();
            var regImportLine = new Regex(@"(?<=(^import {1,})([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,})(\.[a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}) {1,}import {1,}([a-zA-Z\u4E00-\u9FA5][a-zA-Z0-9_\u4E00-\u9FA5]{0,}))");
            var trimChars = new char[] { ' ', };
            for (int i = startLineNumber; i <= endLineNumber; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);
                if (string.IsNullOrWhiteSpace(lineText) || lineText.TrimStart(trimChars).StartsWith("#")) continue;
                var match = regImportLine.Match(lineText);
                if (match.Success)
                {
                    resultList.Add(lineText);
                }
            }
            return resultList;
        }

        /// <summary>
        /// 由 from 和 import 引入的 .net 名字空间
        /// </summary>
        private List<ImportedElement> importedElements = new List<ImportedElement>();

        /// <summary>
        /// 刷新所有使用 import 和 from 语句引入的库。
        /// </summary>
        private void AnalysisImportedElements(int startLineNumber, int endLineNumber)
        {
            importedElements.Clear();
            if (endLineNumber < 1) return;

            var trimChars = new char[] { ' ', '　', '\t', };

            var fromLines = GetFromImportedLine(1, endLineNumber);
            foreach (var line in fromLines)
            {
                var indexOfAs = line.IndexOf(" as ");
                var elementText = "";
                var alias = "";
                if (indexOfAs >= 0)
                {
                    elementText = line.Substring(0, indexOfAs);
                    alias = line.Substring(indexOfAs + 4);
                }

                var newElement = new ImportedElement()
                {
                    Text = elementText,
                    Alias = alias,
                };
                newElement.Type = GetImportedElementType(elementText);
                importedElements.Add(newElement);
            }

            var importLines = GetImportedLine(1, endLineNumber);
            foreach (var line in importLines)
            {
                var elementText = line.Trim(trimChars);
                var newElement = new ImportedElement()
                {
                    Text = elementText,
                };
                newElement.Type = GetImportedElementType(elementText);
                importedElements.Add(newElement);
            }
        }

        private ImportedElementType GetImportedElementType(string elementText)
        {
            if (string.IsNullOrWhiteSpace(elementText)) return ImportedElementType.Unknown;

            // 先看是否 python 包
            var ironPythonLibPath = Globals.InstalledPath + "\\Lib\\";
            string shortPath;
            if (elementText.Contains("."))
            {
                shortPath = elementText.Replace(".", "\\");
            }
            else
            {
                shortPath = elementText;
            }
            shortPath.Trim(new char[] { '\\', '.', });
            if (Directory.Exists(ironPythonLibPath + shortPath)) return ImportedElementType.PythonPackage;

            // 再看是否 python 模块
            if (File.Exists(ironPythonLibPath + shortPath + ".py")) return ImportedElementType.PythonModel;

            // 为提高响应速度（也为了降低实现难度）关于 .net 的名字空间与类，仅提供 建议可用 的相关内容，并不完整。
            // 再看是否 .net 命名空间
            var trimedElementText = elementText.Trim(new char[] { '\\', '.', ' ', '　', '\t', });
            switch (trimedElementText)
            {
                case "LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils":
                case "LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets":
                case "LunarSF.SHomeWorkshop.LunarMarkdownEditor":
                    return ImportedElementType.DotNetNamespace;
            }

            // 再看是否 .net 类
            if (trimedElementText.StartsWith("LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.") ||
                trimedElementText.StartsWith("LunarSF.SHomeWorkshop.LunarMarkdownEditor.Widgets.") ||
                trimedElementText.StartsWith("LunarSF.SHomeWorkshop.LunarMarkdownEditor."))
                return ImportedElementType.DotNetClass;

            return ImportedElementType.Unknown;
        }

        /// <summary>
        /// 查找第一个非 import 且非 from 且非 注释 行且非 空白 行的行号。
        /// </summary>
        /// <returns>如果找不到，则返回 -1。</returns>
        private int GetFirstNoneImportLineNumber()
        {
            var trimChars = new char[] { ' ', };
            for (int i = 1; i <= this.Document.LineCount; i++)
            {
                var line = this.Document.GetLineByNumber(i);
                var lineText = this.Document.GetText(line.Offset, line.Length);

                if (string.IsNullOrWhiteSpace(lineText)) continue;
                if (lineText.Trim(trimChars).StartsWith("#")) continue;
                if (lineText.StartsWith("from ") || lineText.StartsWith("import ")) continue;
                return i;
            }
            return -1;
        }

        #endregion 自动完成


        /// <summary>
        /// 附加新行。
        /// </summary>
        private bool BreakLine()
        {
            var selStartOffset = this.SelectionStart;
            var fstLine = this.Document.GetLineByOffset(selStartOffset);

            var selEndOffset = this.SelectionStart + this.SelectionLength;
            var lstLine = this.Document.GetLineByOffset(selEndOffset);

            var leftText = this.Document.GetText(fstLine.Offset, selStartOffset - fstLine.Offset);
            var midText = this.Document.GetText(selStartOffset, selEndOffset - selStartOffset);
            var rightText = this.Document.GetText(selEndOffset, lstLine.EndOffset - selEndOffset);

            if (leftText.TrimEnd(new char[] { ' ', }).EndsWith(":"))
            {
                var headerSpacesRegex = new Regex(@"^[\t ]{1,}");
                var headerSpacesMatch = headerSpacesRegex.Match(leftText);
                if (headerSpacesMatch.Success)
                {
                    this.Document.Replace(selStartOffset, selEndOffset - selStartOffset, "\r\n" + headerSpacesMatch.Value + "    ");
                    this.Select(fstLine.EndOffset + headerSpacesMatch.Length + 6, 0);
                }
                else
                {
                    this.Document.Replace(selStartOffset, selEndOffset - selStartOffset, "\r\n    ");
                    this.Select(fstLine.EndOffset + 6, 0);
                }
                return true;
            }

            return false;
        }

        /// <summary>
        /// 附加新行。
        /// </summary>
        private void AppendANewLine()
        {
            var curLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
            var text = this.Document.GetText(curLine.Offset, curLine.Length);

            this.Document.Insert(curLine.EndOffset, "\r\n");
            this.Select(curLine.EndOffset + 2, 0);
        }

        /// <summary>
        /// 插入新行。
        /// </summary>
        private void InsertANewLine()
        {
            var curLine = this.Document.GetLineByOffset(this.SelectionStart);
            var text = this.Document.GetText(curLine.Offset, curLine.Length);

            this.Document.Insert(curLine.Offset, "\r\n");
            this.Select(curLine.Offset, 0);
        }

        /// <summary>
        /// 根据选项构建正则表达式。
        /// </summary>
        /// <param name="textToFind">要查找的文本</param>
        /// <param name="leftToRight">正序还是逆序。</param>
        private Regex GetRegEx(string textToFind, bool leftToRight)
        {
            RegexOptions options = RegexOptions.None;
            if (leftToRight)
            {
                options |= RegexOptions.RightToLeft;
            }
            options |= RegexOptions.IgnoreCase;

            string pattern = textToFind; // Regex.Escape(textToFind);
            return new Regex(pattern, options);
        }

        /// <summary>
        /// 跳转到下一个输入区域。这些输入区域包括：成对的小括弧之间，成对的大括弧之间，成对的中括弧之间等等。
        /// </summary>
        /// <param name="e"></param>
        private bool JumpOverMarks(ref KeyEventArgs e, bool isShift)
        {
            if (SelectionLength != 0) return false;
            //只有当插入点正好在某些特殊符号（及符号组合）前面时才起作用，用来跳过这些个特殊符号组合。

            try
            {
                var regexText = "(</?[a-zA-Z]{1,}( [^><]*)?>)|(\\*\\*)|(\\[\\=)|(\\=\\])|(__)|([_\\*“”‘’'\"`<>《》〈〉\\(\\)\\[\\]\\{\\}（）〔〕〈〉「」『』〖〗【】［］｛｝＂＇°])";

                Regex regex = GetRegEx(regexText, isShift);
                int start = regex.Options.HasFlag(RegexOptions.RightToLeft) ? SelectionStart : SelectionStart + SelectionLength;
                Match match = regex.Match(Text, start);

                if (!match.Success)  // start again from beginning or end
                {
                    if (regex.Options.HasFlag(RegexOptions.RightToLeft))
                        match = regex.Match(Text, Text.Length);
                    else
                        match = regex.Match(Text, 0);
                }

                if (match.Success)
                {
                    if (isShift)
                    {
                        if (match.Index + match.Length != SelectionStart) return false;

                        var destSel = match.Index;
                        if (destSel >= 0)
                        {
                            Select(destSel, 0);
                            TextLocation loc = Document.GetLocation(match.Index);
                            ScrollTo(loc.Line, loc.Column);

                            e.Handled = true;
                            return true;
                        }
                    }
                    else
                    {
                        if (match.Index != SelectionStart + SelectionLength) return false;

                        var destSel = match.Index + match.Length;
                        if (destSel <= Document.TextLength)
                        {
                            Select(destSel, 0);
                            TextLocation loc = Document.GetLocation(match.Index);
                            ScrollTo(loc.Line, loc.Column);

                            e.Handled = true;
                            return true;
                        }
                    }

                    return false;
                }

                return false;
            }
            catch (Exception ex)
            {
                LMessageBox.Show(ex.Message, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return false;
            }
        }

        /// <summary>
        /// [覆盖方法]只有用这个办法才能使Alt+Up/Down生效。
        /// </summary>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyboardDevice.Modifiers == ModifierKeys.Alt
                && (e.KeyboardDevice.IsKeyDown(Key.RightAlt) || e.KeyboardDevice.IsKeyDown(Key.LeftAlt)))
            {
                if ((e.Key == Key.Up || e.SystemKey == Key.Up))
                {
                    SwapWithPreviewLine();
                    e.Handled = true;
                }
                else if ((e.Key == Key.Down || e.SystemKey == Key.Down))
                {
                    SwapWithNextLine();
                    e.Handled = true;
                }
            }
            base.OnKeyDown(e);
        }

        /// <summary>
        /// 与后一行交换位置。
        /// </summary>
        internal void SwapWithNextLine()
        {
            var curStartLine = this.Document.GetLineByOffset(this.SelectionStart);
            var curEndLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
            var nextLine = curEndLine.NextLine;

            if (nextLine != null)
            {
                this.BeginChange();
                var lineSplitter = "\n";
                if (this.Document.Text.Contains("\r\n"))
                {
                    lineSplitter = "\r\n";
                }
                var nextLineText = this.Document.GetText(nextLine.Offset, nextLine.Length);
                this.Document.Remove(nextLine.Offset - lineSplitter.Length, nextLine.Length + lineSplitter.Length);//先删除下一行

                var curStartLineOffset = curStartLine.Offset;
                this.Document.Insert(curStartLineOffset, nextLineText + lineSplitter);
                this.EndChange();
            }
        }

        /// <summary>
        /// 与前一行交换位置。
        /// </summary>
        internal void SwapWithPreviewLine()
        {
            var curStartLine = this.Document.GetLineByOffset(this.SelectionStart);
            var curEndLine = this.Document.GetLineByOffset(this.SelectionStart + this.SelectionLength);
            var preLine = curStartLine.PreviousLine;

            if (preLine != null)
            {
                this.BeginChange();
                var preStartLineOffset = preLine.Offset;
                var startOffset = this.SelectionStart - curStartLine.Offset;
                var selLength = this.SelectionLength;

                var lineSplitter = "\n";
                if (this.Document.Text.Contains("\r\n"))
                {
                    lineSplitter = "\r\n";
                }

                var preLineText = this.Document.GetText(preLine.Offset, preLine.Length);
                this.Document.Insert(curEndLine.EndOffset, lineSplitter);
                this.Document.Insert(curEndLine.EndOffset + lineSplitter.Length, preLineText);
                this.Document.Remove(preLine.Offset, preLine.Length + lineSplitter.Length);
                this.EndChange();

                this.Select(preStartLineOffset + startOffset, selLength);
            }
        }

    }

}
